/*
 * cpu_info.c
 *
 * Representación de información sobre una CPU
 *
 */

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "lexer.h"

#include "cpu_info.h"

#define STR_UNKNOWN "Unknown" /* Usado cuando no se encuentra tipo/modelo de CPU */

CpuInfo cpu_info_new (const char *proc_dir) {
	CpuInfo result;
	bstring cpuinfo_path = NULL;
	FILE *f = NULL;
	
	/* Pre: */
	assert (proc_dir != NULL);
	
	/* Armado de la ruta y apertura del archivo */
	cpuinfo_path = bfromcstr (proc_dir);
	bcatcstr (cpuinfo_path, "/cpuinfo");
	f = fopen ((char *)cpuinfo_path->data, "r");
	bdestroy (cpuinfo_path);
	
	result.type = NULL;
	result.model = NULL;
	
	if (f != NULL) {
		Lexer *l = lexer_new (f);
		bstring tag;
		
		/* Recorro línea a línea... */
		while ( (result.type==NULL || result.model==NULL) && 
		        !lexer_is_off (l)
		      ) {
			lexer_next (l, ALPHANUMERIC "_ ");
			if (!lexer_is_off (l)) {
				tag = lexer_item (l);
				/* ...buscando líneas donde la etiqueta `tag' sea... */
				if (biseqcstr (tag, "vendor_id")) {
					/* ...el fabricante. */
					lexer_skip_to (l, ALPHANUMERIC);
					lexer_next_to (l, "\n");
					result.type = lexer_item (l);
				} else if (biseqcstr (tag, "model name")) {
					/* ...o el modelo. */
					lexer_skip_to (l, ALPHANUMERIC);
					lexer_next_to (l, "\n");
					result.model = lexer_item (l);
				} else {
					lexer_skip_to (l, "\n");
				}
				lexer_skip (l, "\n");
				bdestroy (tag);
			}
		}
		lexer_destroy (l);
		fclose (f);
	}
	/* Manejar errores de parseo: */
	if (result.type == NULL) {
		result.type = bfromcstr (STR_UNKNOWN);
	}
	if (result.model == NULL) {
		result.model = bfromcstr (STR_UNKNOWN);
	}

	assert (result.type != NULL);
	assert (result.model != NULL);
	
	return result;
}

CpuInfo cpu_info_destroy (CpuInfo self) {
	bdestroy (self.type); self.type = NULL;
	bdestroy (self.model); self.model = NULL;
	return self;
}
